// $URL: http://mingw-lib.googlecode.com/svn/trunk/working/avcodec_to_widget_10/t_av_packet.h $
// $Rev: 344 $
// $Author: akio.miyoshi $
// $Date:: 2010-08-02 12:42:15 +0000#$

#ifndef T_AV_PACKET_H
#define T_AV_PACKET_H

#include "stable.h"
#include "avcodec/t_avcodec.h"

struct T_AV_Audio_Decode_Buffer
{
    DECLARE_ALIGNED(16,quint8,decode_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    DECLARE_ALIGNED(16,quint8,convert_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
};

class T_AV_Packet : public T_RecursiveAtomicObject
{
    Q_OBJECT
protected:
    AVPacket m_av_packet;
    qint64 m_timing;
protected:
    AVFormatContext *m_format_ctx;
    AVStream *m_stream;
    AVCodecContext *m_codec_ctx;
#if 0x0
    AVFrame *m_video_frame;
#else
    T_AVFrame *m_video_frame;
#endif
    T_AVPicture *m_video_picture;
    QImage m_video_image;
public:
    explicit T_AV_Packet(AVFormatContext *a_format_ctx, AVPacket *a_av_packet);
    explicit T_AV_Packet(qint64 a_timing);
    ~T_AV_Packet();
    int streamIndex()
    {
        if(this->isNull())
        {
            return -1;
        }
        return m_av_packet.stream_index;
    }
    //[isNull()]
    bool isNull()
    {
        return (m_stream==NULL);
    }
    //[isDecoded()]
    bool isDecoded()
    {
        return (m_video_frame != NULL);
    }
    //[decodeAudio()]
    QByteArray decodeAudio(T_AV_Audio_Decode_Buffer *a_decode_buff);
    //[decodeVideoToNull()]
    bool decodeVideoToNull(bool a_make_copy = false);
    //[decodeToQImage()]
    QImage decodeVideoToQImage(T_AVPicture *a_decode_buff, const QSize &a_size, int a_depth);
    //[timing()] returns packets pts in milliseconds
    qint64 timing()
    {
        return m_timing;
    }
    int frameNo()
    {
        return m_frame_no;
    }
protected:
    friend class T_AV_Packet_Queue;
protected:
    int m_frame_no;
};

class T_AV_Packet_Queue : public T_RecursiveLockedObject
{
    Q_OBJECT
protected:
    class T_Box_Player_Context *m_player_ctx;
    QQueue< QSharedPointer<T_AV_Packet> > m_packet_queue;
    int m_enqueue_count;
    bool m_complete;
    qint64 m_max_timing;
    T_RecursiveAtomic m_atomic;
public:
    explicit T_AV_Packet_Queue(class T_Box_Player_Context *a_player_ctx)
        : m_player_ctx(a_player_ctx)
        , m_enqueue_count(0)
        , m_complete(false)
        , m_max_timing(-1)
    {
    }
    ~T_AV_Packet_Queue()
    {
    }
    bool isComplete()
    {
        return m_complete;
    }
    int size()
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        return m_packet_queue.size();
    }
    void clear()
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        //m_packet_queue.clear();
        while(m_packet_queue.size()>0)
        {
            QSharedPointer<T_AV_Packet> v = m_packet_queue.dequeue();
            Q_UNUSED(v);
        }
        m_enqueue_count = 0;
        m_complete = false;
        m_max_timing = -1;
    }
    void enqueue(T_AV_Packet *a_av_packet);
    QSharedPointer<T_AV_Packet> dequeue()
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        if(m_packet_queue.size()==0) return QSharedPointer<T_AV_Packet>(NULL);
        return m_packet_queue.dequeue();
    }
    QSharedPointer<T_AV_Packet> head()
    {
        QMutexLocker v_lock(&m_atomic);
        Q_UNUSED(v_lock);
        if(m_packet_queue.size()==0) return QSharedPointer<T_AV_Packet>(NULL);
        return m_packet_queue.head();
    }
    QSharedPointer<T_AV_Packet> last()
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        if(m_packet_queue.size()==0) return QSharedPointer<T_AV_Packet>(NULL);
        return m_packet_queue.last();
    }
    QSharedPointer<T_AV_Packet> value(int i)
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        if(i<0) return QSharedPointer<T_AV_Packet>(NULL);
        if(i>=m_packet_queue.size()) return QSharedPointer<T_AV_Packet>(NULL);
        return m_packet_queue.value(i);
    }
#if 0x0
    box_deprecated qint64 duration()
    {
        QMutexLocker v_lock(this);Q_UNUSED(v_lock);
        if(m_complete)
        {
            return LONG_LONG_MAX;
        }
        if(packet_queue.size()==0) return 0;
        return (last()->timing() - head()->timing());
    }
#endif
    qint64 max_timing()
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        return m_max_timing;
    }
    qint64 duration(qint64 a_now_msec)
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        if(m_complete)
        {
            return LONG_LONG_MAX;
        }
        if(m_max_timing<0)
        {
            return 0;
        }
        qint64 v_ahead = m_max_timing - a_now_msec;
        if(v_ahead < 0)
        {
            return 0;
        }
        return v_ahead;
    }
    qint64 decodedCount(qint64 a_max)
    {
        QMutexLocker v_lock(&m_atomic);Q_UNUSED(v_lock);
        if(m_complete)
        {
            if(m_packet_queue.size()==0) return LONG_LONG_MAX;
            if(m_packet_queue.last()->isDecoded()) return LONG_LONG_MAX;
        }
        int v_count = 0;
        for(int i=0; i<m_packet_queue.size(); i++)
        {
            if(!m_packet_queue.value(i)->isDecoded())
            {
                return i;
            }
            v_count = i + 1;
            if(a_max >= 0)
            {
                if(v_count >= a_max)
                {
                    return v_count;
                }
            }
        }
        return m_packet_queue.size();
    }
};

#endif // T_AV_PACKET_H
